package nbcp


import nbcp.comm.*
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.cloud.gateway.route.RouteLocator
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder
import org.springframework.context.ApplicationContext
import org.springframework.context.annotation.Bean
import org.springframework.web.reactive.config.WebFluxConfigurer
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod
import org.springframework.http.HttpStatus
import org.springframework.web.cors.reactive.CorsUtils
import org.springframework.web.server.ServerWebExchange
import org.springframework.web.server.WebFilter
import org.springframework.web.server.WebFilterChain
import reactor.core.publisher.Mono
import java.net.URI


@Configuration
class WebFluxConfig : WebFluxConfigurer {

//    class RemoteAddrKeyResolver : KeyResolver {
//        override fun resolve(exchange: ServerWebExchange): Mono<String> {
//            var path = exchange.getRequest().getPath().value();   //用户访问的接口地址
//            return Mono.just(path);
//        }
//    }

//    @Bean(name = ["remoteAddrKeyResolver"])
//    fun remoteAddrKeyResolver(): RemoteAddrKeyResolver {
//        return RemoteAddrKeyResolver()
//    }
//
//    @Bean(name = ["redisRateLimiter"])
//    public fun customRedisRateLimiter(): RedisRateLimiter {
//        var customRedisRateLimiter = RedisRateLimiter(100, 100);
//        customRedisRateLimiter.setApplicationContext(applicationContext);
//        return customRedisRateLimiter;
//    }

    @Bean
    fun authorizationFilter(): AuthorizationFilter {
        return AuthorizationFilter()
    }


    @Autowired
    lateinit var applicationContext: ApplicationContext;

//    @Autowired
//    lateinit var redisRateLimiter: RedisRateLimiter

//    @Bean
//    fun myRoutes(builder: RouteLocatorBuilder
////                 ,@Qualifier("remoteAddrKeyResolver") remoteAddrKeyResolver: RemoteAddrKeyResolver
////                 ,@Qualifier("redisRateLimiter") redisRateLimiter: RedisRateLimiter
//    ): RouteLocator {
//        return builder.routes()
////                .route { p ->
////                    p
////                        .predicate {
////                            it.addUrlTransformer { "/corp/**" }
////                            true
////                        }
////                        .filters { f ->
////                            f.stripPrefix(1)
////
////    //                                f.requestRateLimiter { config ->
////    //                                    //                                    var d = RedisRateLimiter(100, 30);
////    ////                                    it.rateLimiter = d;
////    //                                    config.rateLimiter = redisRateLimiter
////    //                                    config.keyResolver = remoteAddrKeyResolver
////    //                                }
//////                            f.hystrix {
//////                                it.fallbackUri = URI("forward:fallback")
//////                            }
////                        }
////                        .uri("lb://corp-api/**")
////                }
//
////                .route{p->
////                    p.predicate{ it.request.method == HttpMethod.OPTIONS}.out
////                }
//                .route { p ->
//                    p.predicate {
//                        it.request.path.subPath(1, 2).toString().equals("corp", true)
//                    }
//                            .filters {
//                                it.stripPrefix(1)
//                                it.hystrix {
//                                    it.fallbackUri = URI("forward:fallback")
//                                }
//                            }
//                            .uri("lb://corp-api/**")
//                }
//                .route { p ->
//                    p.predicate {
//                        it.request.path.subPath(1, 2).toString().equals("shop", true)
//                    }
//                            .filters {
//                                it.stripPrefix(1)
//
//                                it.hystrix {
//                                    it.fallbackUri = URI("forward:fallback")
//                                }
//                            }
//                            .uri("lb://shop-api/**")
//                }
//                .build()
//    }


    @Bean
    fun corsFilter(): WebFilter {
        val MAX_AGE = "86400"; //秒

        return object : WebFilter {
            override fun filter(ctx: ServerWebExchange, chain: WebFilterChain): Mono<Void> {

                var request = ctx.getRequest();
                if (CorsUtils.isCorsRequest(request)) {
                    var requestHeaders = request.headers;
                    var response = ctx.getResponse();
                    var requestMethod = requestHeaders.accessControlRequestMethod;
                    var headers = response.headers;
                    headers.set(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.origin);
                    headers.set(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.accessControlRequestHeaders);

                    if (requestMethod != null) {
                        headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name);
                    }

                    headers.set(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
                    headers.set(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
                    headers.set(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);


                    var allowHeaders = mutableListOf<String>();

                    if (request.method == HttpMethod.OPTIONS) {
                        allowHeaders.addAll(requestHeaders.get("Access-Control-Request-Headers")?.filter { it.HasValue }
                                ?: listOf())
                    }

                    if (allowHeaders.any() == false) {
                        allowHeaders = requestHeaders.keys.toMutableList()

                        //https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
                        var standardHeaders = arrayOf(
                                "expires",
                                "cache-control",
                                "content-language",
                                "content-type",
                                "last-modified",
                                "pragma",
                                "origin",
                                "accept",
                                "user-agent",
                                "connection",
                                "host",
                                "accept-language",
                                "accept-encoding"
                        )
                        //移除标准 header
                        allowHeaders.removeAll { standardHeaders.contains(it.toLowerCase()) }
                    }

                    if (allowHeaders.any()) {
                        headers.set("Access-Control-Allow-Headers", allowHeaders.joinToString(","))
                    }

                    if (request.method == HttpMethod.OPTIONS) {
                        response.statusCode = HttpStatus.OK;
                        return Mono.empty();
                    }
                }
                return chain.filter(ctx);
            }
        }
    }
}